package com.yb.guigu.pick.activity.util;

import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Copyright (C), 2022-2023, 姚兵
 * Author: 32210
 * Date: 2023/7/15 14:17
 * FileName: SplitRedPackageUtil
 * Description:
 */

@Slf4j
public class SplitRedPackageUtil {

    static Random random=new Random();
    static BigDecimal min= new BigDecimal("0.1");
    /**
     * 拆红包的算法--->二倍均值算法
     *
     * @param totalMoney
     * @param redPackageNumber
     * @return
     */
    public static BigDecimal[] splitRedPackageAlgorithm(BigDecimal totalMoney, int redPackageNumber) {
        BigDecimal[] redPackageNumbers = new BigDecimal[redPackageNumber];
        //已经被抢夺的红包金额,已经被拆分塞进子红包的金额
        BigDecimal useMoney = new BigDecimal(0);

        for (int i = 0; i < redPackageNumber; i++) {
            if (i == redPackageNumber - 1) {
                redPackageNumbers[i] = totalMoney.subtract(useMoney).setScale(2,RoundingMode.HALF_UP);;
            } else {
                //二倍均值算法，每次拆分后塞进子红包的金额 = 随机区间(0,(剩余红包金额M ÷ 未被抢的剩余红包个数N) * 2)
                BigDecimal avgMoney = ((totalMoney.subtract(useMoney)).divide(new BigDecimal(redPackageNumber - i),RoundingMode.HALF_UP)) .multiply( new BigDecimal(2));
                double doubleValue = random.nextDouble();

                BigDecimal random = new BigDecimal(doubleValue).setScale(2, RoundingMode.HALF_UP).multiply(avgMoney.subtract(min));
                redPackageNumbers[i] =  min.add(random).setScale(2,RoundingMode.HALF_UP);
            }
            useMoney = useMoney.add(redPackageNumbers[i]);
        }
        return redPackageNumbers;
    }

    public static List<BigDecimal> splitRedPackageRandomNumber(BigDecimal totalAmount, BigDecimal min, BigDecimal max){

        BigDecimal remainAmount= BigDecimal.valueOf(totalAmount.doubleValue());

        Random random = new Random();

        List<BigDecimal> resultList=new ArrayList<>();

        BigDecimal subtract = max.subtract(min);

        while (true){


            double result = random.nextDouble() * subtract.doubleValue() + 0.1;

            BigDecimal randomAmount = new BigDecimal(result).setScale(2, RoundingMode.HALF_UP);


            //剩余金额小于随机金额，则使用剩余金额
            if(remainAmount.compareTo(randomAmount)<0){
                resultList.add(remainAmount);
                break;
            }
            resultList.add(randomAmount);
            remainAmount = remainAmount.subtract(randomAmount);

        }

        return resultList;
    }


    /**
     *
     * @param totalAmount
     * @param min 最小金额
     * @param max 最大金额
     * @param totalCount  红包个数，总金额
     * @return
     */
    public static List<BigDecimal> splitRedPackagePreciseNumber( BigDecimal totalAmount,BigDecimal min,BigDecimal max,int totalCount){

        if(min.compareTo(max)>0){
            throw new RuntimeException("最小金额不能大于最大金额");
        }

        //剩余个数
        int remainCount=totalCount;

        //最小金额总计
        BigDecimal minSumAmount;

        BigDecimal minSum = min.multiply(BigDecimal.valueOf(totalCount));
        BigDecimal maxSum = max.multiply(BigDecimal.valueOf(totalCount));

        if(minSum.compareTo(totalAmount)>0){
            throw new RuntimeException("最小金额过大");
        }

        if(maxSum.compareTo(totalAmount)<0){
            throw new RuntimeException("最大金额过小");
        }

        if(maxSum.compareTo(totalAmount)==0){
            BigDecimal finalMax = max;
            return Stream.iterate(0, i->i+1).limit(totalCount).map(item->BigDecimal.valueOf(finalMax.doubleValue())).collect(Collectors.toList());
        }

        if(minSum.compareTo(totalAmount)==0){
            return Stream.iterate(0, i->i+1).limit(totalCount).map(item->BigDecimal.valueOf(min.doubleValue())).collect(Collectors.toList());
        }

        //剩余金额
        BigDecimal remainAmount= BigDecimal.valueOf(totalAmount.doubleValue()).setScale(2,RoundingMode.HALF_UP);

        Random random = new Random();

        BigDecimal[]  arr= new BigDecimal[totalCount];

        int curIndex=0;




        while (remainCount>0){

            max=max.compareTo(remainAmount)>0?remainAmount:max;

            BigDecimal subtract = max.subtract(min);

            double doubleResult = (random.nextDouble() * subtract.doubleValue()) + min.doubleValue();



            BigDecimal randomAmount = BigDecimal.valueOf(doubleResult).setScale(2,RoundingMode.HALF_UP);

            remainCount--;

            minSumAmount=min.multiply(BigDecimal.valueOf(remainCount)).setScale(2,RoundingMode.HALF_UP);

            log.info("random:{}  remain:{} minSum:{}",randomAmount,remainAmount,minSumAmount);



            if(remainAmount.compareTo(randomAmount)<0){
                randomAmount=BigDecimal.valueOf(remainAmount.doubleValue());
            }else{
                remainAmount=remainAmount.subtract(randomAmount).setScale(2,RoundingMode.HALF_UP);
            }


            if(remainAmount.compareTo(BigDecimal.ZERO)<=0){
                break;
            }

            //如果剩余金额不够分了，需要将这个金额拆分到剩余金额
            if(remainAmount.compareTo(minSumAmount)<=0){
                BigDecimal remain = minSumAmount.subtract(remainAmount).setScale(2,RoundingMode.HALF_UP);
                randomAmount=randomAmount.subtract(remain).setScale(2,RoundingMode.HALF_UP);
                arr[curIndex++]=randomAmount;
                remainAmount=remainAmount.subtract(randomAmount).setScale(2,RoundingMode.HALF_UP);
                log.info("remainAmount:{}",remainAmount);
                while(remainCount>0){
                    arr[curIndex++]=min;
                    remainCount--;
                }
                remainAmount=BigDecimal.ZERO;
                break;
            }

            arr[curIndex++]=randomAmount;

        }



        //如果循环结束还有剩余金额，则将最小的金额加上剩余金额
        if(remainAmount.compareTo(BigDecimal.ZERO)>0){
            int minIndex=0;
            BigDecimal minItem=arr[minIndex];

            //找出最小的
            for(int i=1;i<arr.length;i++){
                if(minItem.compareTo(arr[i])>0){
                    minItem=arr[i];
                    minIndex=i;
                }
            }

            //将最小的加上剩余的金额
            arr[minIndex]=minItem.add(remainAmount);
        }
        List<BigDecimal> resultList = Arrays.asList(arr);

        Collections.shuffle(resultList);

        return resultList;
    }


}
